#pragma once

#include "kconfig.h"
#include "ktypes.h"

struct KObject
{
	KType Type;

	union
	{
		k_int  v_int;
		k_real v_real;
	};
	k_string   v_string;

	KObject() : Type(K_INT), v_int(0) {}

	KObject(KType type) : Type(type)
	{
		switch (type)
		{
		case K_INT:
			this->v_int = (k_int)0;
			break;
		case K_REAL:
			this->v_real = (k_real)0;
			break;
		case K_STRING:
			this->v_string = k_string("");
			break;
		}
	}

	KObject(k_int v) : Type(K_INT), v_int(v) {}

	KObject(k_real v) : Type(K_REAL), v_real(v) {}

	KObject(k_string v) : Type(K_STRING), v_string(v) {}

	KObject(bool v) : Type(K_INT) { this->v_int = v ? (k_int)1 : (k_int)0; }

	KObject(const char* v) : Type(K_STRING), v_string(v) {}

	KObject(const KObject &src)
	{
		this->Type = src.Type;
		switch (src.Type)
		{
		case K_INT:
			this->v_int = src.v_int;
			break;
		case K_REAL:
			this->v_real = src.v_real;
			break;
		case K_STRING:
			this->v_string = src.v_string;
			break;
		}
	}

	k_int ToInt() const;

	k_real ToReal() const;

	k_string ToString() const;

	operator bool() const;

	KObject& operator =(const KObject &rhs);

	KObject operator +(const KObject &rhs) const;

	KObject operator -(const KObject &rhs) const;

	KObject operator -() const;

	KObject operator *(const KObject &rhs) const;

	KObject operator /(const KObject &rhs) const;

	KObject operator %(const KObject &rhs) const;

	KObject operator ==(const KObject &rhs) const;

	KObject operator !=(const KObject &rhs) const;

	KObject operator <(const KObject &rhs) const;

	KObject operator <=(const KObject &rhs) const;

	KObject operator >(const KObject &rhs) const;

	KObject operator >=(const KObject &rhs) const;

	KObject operator &&(const KObject &rhs) const;

	KObject operator ||(const KObject &rhs) const;

	KObject operator ^(const KObject &rhs) const;

	KObject operator !() const;

	static KObject IntDiv(const KObject &lhs, const KObject &rhs);

	static KObject Pow(const KObject &lhs, const KObject &rhs);

	static KObject Concat(const KObject &lhs, const KObject &rhs);

	friend std::ostream& operator <<(std::ostream &os, const KObject &obj);

	inline static KType HigherType(const KType a, const KType b) { return a > b ? a : b; }
};
